package com.freestyle.seatabusiness.account.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.ServiceConfig;
import org.apache.dubbo.config.context.ModuleConfigManager;
import org.apache.dubbo.config.deploy.DefaultModuleDeployer;
import org.apache.dubbo.config.spring.util.DubboBeanUtils;
import org.apache.dubbo.metadata.MetadataInfo;
import org.apache.dubbo.metadata.WritableMetadataService;
import org.apache.dubbo.rpc.model.ModuleModel;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ApplicationContextEvent;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Dubbo服务提供者服务信息打印配置：在服务启动完成后显示本服务提供的api服务以及本服务的ip/port,便于方便调试
 * Created by rocklee on 2022/3/25 16:13
 */
@Configuration
@Slf4j
public class DubboAppListener extends ApplicationContextEvent implements ApplicationListener<ApplicationReadyEvent> {
  private ModuleModel moduleModel;
  /**
   * Create a new ContextStartedEvent.
   *
   * @param source the {@code ApplicationContext} that the event is raised for
   *               (must not be {@code null})
   */
  public DubboAppListener(ApplicationContext source) {
    super(source);
    this.moduleModel = DubboBeanUtils.getModuleModel(source);
  }

  @Override
  public void onApplicationEvent(ApplicationReadyEvent event) {
    DefaultModuleDeployer defaultModuleDeployer= (DefaultModuleDeployer) moduleModel.getDeployer();
    try {
      Field field=DefaultModuleDeployer.class.getDeclaredField("configManager");
      field.setAccessible(true);
      ModuleConfigManager configManager= (ModuleConfigManager) field.get(defaultModuleDeployer);
      if (configManager.getServices().size()>0){
        ServiceConfig serviceConfigBase= (ServiceConfig) configManager.getServices().iterator().next();
        field=ServiceConfig.class.getDeclaredField("localMetadataService");
        field.setAccessible(true);
        WritableMetadataService metadataService= (WritableMetadataService) field.get(serviceConfigBase);
        String host=metadataService.getMetadataServiceURL().getHost();
        int port=metadataService.getMetadataServiceURL().getPort();
        StringBuilder sb=new StringBuilder();
        sb.append("====================================\n");
        sb.append("Dubbo service is ready:\n");
        for (Map.Entry<String, MetadataInfo> e:metadataService.getMetadataInfos().entrySet()){
          sb.append(e.getValue().getServices().entrySet().stream().map(i->"   "+i.getKey()).collect(Collectors.joining("\n"))+"\n");
        }
        sb.append("Provider IP:"+host+"\n");
        sb.append("Provider port:"+port+"\n");
        sb.append("nacos.register.server-addr:"+serviceConfigBase.getRegistries().stream().map(i->i.getAddress()).collect(Collectors.joining(","))+"\n");
        sb.append("====================================");
        CompletableFuture.runAsync(()->{
           log.info(sb.toString());
        },CompletableFuture.delayedExecutor(3, TimeUnit.SECONDS));
      }
    } catch (NoSuchFieldException | IllegalAccessException e) {
      e.printStackTrace();
    }
  }
}
